/*
 *  scoreBoard - OscDataReceiver.cpp
 *  Copyright 2011 W. Reckman. All rights reserved.
 */
#include "Settings.h"
#include "ScoreBoardApp.h"
#include "OscDataReceiver.h"

const string OscDataReceiver::LOG_FILE_NAME = "levelup-event-data.log";

const string OscDataReceiver::OSC_ADDR_GAME_BALANCE = "/levelUp/game/balance"; //1*float (-0.5=culture, 0=balance, 0.5=industry)
const string OscDataReceiver::OSC_ADDR_GAME_STATE_OLD = "/levelUp/game/state/old";
const string OscDataReceiver::OSC_ADDR_GAME_STATE_NEW = "/levelUp/game/state/new";

const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_DATE = "/levelUp/game/player/date"; //2*int (month, day)
const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_TIME = "/levelUp/game/player/time"; //3*int (hours, minutes, seconds)
const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_TARGETS = "/levelUp/game/player/targets"; //2*int (culture, industry)
const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_ID = "/levelUp/game/player/id"; //int (id)
const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_IMAGES = "/levelUp/game/player/images"; //2*string (topImg, bottomImg)
const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_COLOR = "/levelUp/game/player/color"; //3*int (r, g, b)
const string OscDataReceiver::OSC_ADDR_GAME_PLAYER_PICKUPS = "/levelUp/game/player/pickups"; //2*int (goodPickups, badPickups)


OscDataReceiver::OscDataReceiver( ScoreBoardApp& appRef_ )
: s( Settings::getInstance() ), appRef( appRef_ )
{
	hasPrevState = false;
	hasDate = hasTime = hasTargets = hasId = hasImages = hasColor = hasPickups = false;
}

OscDataReceiver::~OscDataReceiver() {
	logFile.close();
}


void OscDataReceiver::setup() {
	int gamePort = ofToInt( *s.getValue( "game_port", "8766" ) );
	
	ofLog( OF_LOG_NOTICE, "(OscDataReceiver.cpp) listening for OSC messages on port %i", gamePort );
	oscReceiver.setup( gamePort );
	
	logFile.open( ofToDataPath( LOG_FILE_NAME ).c_str(), ios::out | ios::app );
	
	if ( ! logFile.is_open() ) {
		ofLog( OF_LOG_ERROR, "(OscDataReceiver.cpp) could not open log file '%s'", LOG_FILE_NAME.c_str() );
	}
}

void OscDataReceiver::update() {
	while ( oscReceiver.hasWaitingMessages() ) {
		BoardModel& board = appRef.getBoard();
		ofxOscMessage msg;
		oscReceiver.getNextMessage( &msg );
//ofLog( OF_LOG_NOTICE, "---Received OSC message with address '%s'", msg.getAddress().c_str() ); //TEMP
		
		if ( msg.getAddress() == OSC_ADDR_GAME_BALANCE ) {
			float balance = msg.getArgAsFloat( 0 );
			logBalanceChange( balance );
			board.setBalance( balance );
		}
		
		if ( msg.getAddress() == OSC_ADDR_GAME_STATE_OLD ) {
			hasPrevState = true;
			prevState = lookupGameStateText( msg.getArgAsString( 0 ) );
		}
		if ( msg.getAddress() == OSC_ADDR_GAME_STATE_NEW ) {
			if ( hasPrevState ) {
				GAME_STATE currState = lookupGameStateText( msg.getArgAsString( 0 ) );
				logStateChange( prevState, currState );
				board.changeGameState( prevState, currState );
				hasPrevState = false;
			}
		}
		
		if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_DATE ) {
			infoTemp.month = msg.getArgAsInt32( 0 ); infoTemp.day = msg.getArgAsInt32( 1 ); hasDate = true;
		} else if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_TIME ) {
			infoTemp.hours = msg.getArgAsInt32( 0 ); infoTemp.minutes = msg.getArgAsInt32( 1 ); infoTemp.seconds = msg.getArgAsInt32( 2 ); hasTime = true;
		} else if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_TARGETS ) {
			infoTemp.cultureTgt = msg.getArgAsInt32( 0 ); infoTemp.industryTgt = msg.getArgAsInt32( 1 ); hasTargets = true;
		} else if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_ID ) {
			infoTemp.id = msg.getArgAsInt32( 0 ); hasId = true;
		} else if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_IMAGES ) {
			infoTemp.topImagePath = new string( msg.getArgAsString( 0 ) ); infoTemp.bottomImagePath = new string( msg.getArgAsString( 1 ) ); hasImages = true;
		} else if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_COLOR ) {
			infoTemp.color.r = msg.getArgAsInt32( 0 ); infoTemp.color.g = msg.getArgAsInt32( 1 ); infoTemp.color.b = msg.getArgAsInt32( 2 ); hasColor = true;
		} else if ( msg.getAddress() == OSC_ADDR_GAME_PLAYER_PICKUPS ) {
			infoTemp.goodPickups = msg.getArgAsInt32( 0 ); infoTemp.badPickups = msg.getArgAsInt32( 1 ); hasPickups = true;
		}
		
		//NOTE: logging must be done before creating the playerhead because the latter deletes the image path strings
		if ( hasDate && hasTime && hasTargets && hasId && hasImages && hasColor && hasPickups ) {
			logPlayerStats( infoTemp );
			board.createPlayerHead( infoTemp );
			hasDate = hasTime = hasTargets = hasId = hasImages = hasColor = hasPickups = false;
		}
	}
}


/*********************
 * PRIVATE FUNCTIONS *
 *********************/

void OscDataReceiver::logBalanceChange( float balance_ ) {
	logFile << ofGetHours() << ":" << ofGetMinutes() << ":" << ofGetSeconds() << " BALANCE -";
	logFile << " balance:{" << balance_ << "}";
	logFile << std::endl;
}

void OscDataReceiver::logStateChange( GAME_STATE prevState_, GAME_STATE currState_ ) {
	logFile << ofGetHours() << ":" << ofGetMinutes() << ":" << ofGetSeconds() << " STATE -";
	logFile << " state:{" << getOscGameStateName( prevState_ ) << ", " << getOscGameStateName( currState_ ) << "}";
	logFile << std::endl;
}

void OscDataReceiver::logPlayerStats( BoardModel::PlayerInfo info_ ) {
	logFile << ofGetHours() << ":" << ofGetMinutes() << ":" << ofGetSeconds() << " PLAYER -";
	logFile << " date:{" << info_.month << ", " << info_.day << "}";
	logFile << " time:{" << info_.hours << ", " << info_.minutes << ", " << info_.seconds << "}";
	logFile << " targets:{" << info_.cultureTgt << ", " << info_.industryTgt << "}";
	logFile << " id:{" << info_.id << "}";
	logFile << " images:{" << *info_.topImagePath << ", " << *info_.bottomImagePath << "}";
	logFile << " color:{" << info_.color.r << ", " << info_.color.g << ", " << info_.color.b << "}";
	logFile << " pickups:{" << info_.goodPickups << ", " << info_.badPickups << "}";
	logFile << std::endl;
}
